Fragment Colocation
https://gql-tada.0no.co/guides/fragment-colocation
概要
Colocation: 一緒に(co-)配置する(location)
GraphQL クエリと UI コンポーネント を一緒に配置するパターン
GraphQL を用いると、各コンポーネントが「自身の必要なデータ」を GraphQL の Fragment を使って定義可能
これを活用して UI コンポーネントと GraphQL のツリーを 相似形 にすると、「コンポーネントがどのようなデータを必要とするのか」をうまく対応付けられる
イメージ
code:_
App Query
└ Post component └ Post fragment
└ Author component └ Author fragment
メリット
コンポーネントに変更があって必要なデータが増減したとき、修正するファイルはそのコンポーネントに閉じる ため 保守性 が向上する
フィールドの増減に気が付きやすいため、Over-fetching のリスクも低くなる
具体例
urql + GraphQL-Codegen
Fragment の定義
code:src/Post.tsx
import { graphql } from "./gql";
const PostFragment = graphql(`
fragment PostFragment on Post {
title
body
author {
...AuthorFragment
}
}
`);
code:src/Author.tsx
import { graphql } from "./gql";
const AuthorFragment = graphql(`
fragment AuthorFragment on Author {
name
}
`);
Fragment に対応するデータを Props で受け取るようにする
code:src/Post.tsx
import { Author } from "./Author";
import { FragmentType, useFragment } from "./gql";
export const Post = ({
postFragment,
}: {
postFragment: FragmentType<typeof PostFragment>;
}) => {
const post = useFragment(PostFragment, postFragment);
return (
<>
<h2>{post.title}</h2>
<div>{post.body}</div>
<Author authorFragment={post.author} />
</>
);
};
GraphQL-Codegen で生成された useFragment を用いると、Fragment で取得したデータにアクセスできる
useFragment の戻り値は、 GraphQL-Codegen を通じて生成した GraphQL の Fragment に対応する型 が付与されている
https://scrapbox.io/files/66f3f87a672220001d6f719c.png
これにより、Post の publishedAt を表示したいとなった場合、{post.publishedAt} と書いてもエラーを吐く
実装者は、Fragment を修正して新しい情報を取得する必要があることに気付ける
また、Post からは Author の詳細な情報を読み取れないようになっている
https://scrapbox.io/files/66f3fb16876bb3001c6e419f.png
GraphQL-Codegen の Fragment Masking によるもの
/wada-blog/Fragment Masking で Fragment Colocation を強制する
https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#fragment-masking
責務の分離 を強制できる radish-miyazaki.icon